/**
 * BaseCanvasElement类, 代表一个基本canvas中的元素(某些方法仅适用矩形元素,圆形就不适合,比如 boundaryRestrict() )
 * @constructor 
 * @param {Object} options BaseCanvasElement的参数
 * @param {number} [options.x=0] 元素的横坐标
 * @param {number} [options.y=0] 元素的纵坐标
 * @param {number} [options.width=10] 元素的宽度
 * @param {number} [options.height=10] 元素的高度
 * @param {number} [options.vx=1] x方向上每次移动的距离
 * @param {number} [options.vy=1] y方向上每次移动的距离
 * @param {number[]} [options.boundaryCoordinates=[]] 元素的边界
 */
function BaseCanvasElement(options) {
  options = Object.assign({}, {
    x: 0,
    y: 0,
    width: 10,
    height: 10,
    vx: 5,
    vy: 5,
    boundaryCoordinates: []
  }, options);
  this.x = options.x;
  this.y = options.y;
  this.width = options.width;
  this.height = options.height;
  this.vx = options.vx;
  this.vy = options.vy;
  this.boundaryCoordinates = options.boundaryCoordinates;
  // 标记元素是否应该被移除（这是一个很重要的属性）
  this.shouldRemove = false;
}

/**
 * shouldDraw方法 
 */
BaseCanvasElement.prototype.shouldDraw = function() {
  return !this.shouldRemove;
}

/**
 * draw方法 当shouldDraw()返回true时才调用render()方法
 * @param {object} context 画布的 context 对象
 */
BaseCanvasElement.prototype.draw = function (context) {
  if(this.shouldDraw()) {
    this.render(context);
  }
}

/**
 * render方法 默认是根据属性在画布上绘制出实例,绘制结果应该只和当前的属性有关
 * @param {object} context 画布的 context 对象
 * @abstract
 */
BaseCanvasElement.prototype.render = function(context) {
  throw new Error('not implemented');
}

/**
 * move方法 控制实例朝上下左右四个方向移动，每次只能向一个方向移动
 * @param {string} direction 移动的方向，可以是 'up', 'down', 'left', 'right' 分别对应上下左右。
 * @param {number} [num] 移动的距离, 可选, 默认值为 this.vx 或 this.vy
 */
BaseCanvasElement.prototype.move = function (direction, num) {
  switch (direction) {
    case 'left':
      this.x -= num || this.vx;
      break;
    case 'right':
      this.x += num || this.vx;
      break;
    case 'up':
      this.y -= num || this.vy;
      break;
    case 'down':
      this.y += num || this.vy;
      break;
    default:
      break;
  }
}

/**
 * destroy方法
 */
BaseCanvasElement.prototype.destroy = function() {
  this.shouldRemove = true;
}

/**
 * boundaryRestrict方法,当元素超出边界后,可以修正元素的位置,确保元素在边界中
 * @param {number[]} [boundaryCoordinates] 边界的范围
 * @param {boolean} ignore 当元素超出边界后是否不主动修正元素的位置
 * @returns {object|boolean} 超出边界将返回详细情况,否则返回false
 */
BaseCanvasElement.prototype.boundaryRestrict = function (boundaryCoordinates, ignore) {
  boundaryCoordinates = boundaryCoordinates || this.boundaryCoordinates;
  var minX = boundaryCoordinates[0];
  var maxX = boundaryCoordinates[2];
  var minY = boundaryCoordinates[1];
  var maxY = boundaryCoordinates[3];
  var rs = {
    top: false,
    bottom: false,
    left: false,
    right: false
  }
  // x方向
  if (typeof minX === 'number' && this.x < minX) {
    !ignore && (this.x = minX);
    rs.left = true;
  }
  if (typeof maxX === 'number' && this.x + this.width > maxX) {
    !ignore && (this.x = maxX - this.width);
    rs.right = true;
  }
  // y方向
  if (typeof minY === 'number' && this.y < minY) {
    !ignore && (this.y = minY);
    rs.top = true;
  }
  if (typeof maxY === 'number' && this.y + this.height > maxY) {
    !ignore && (this.y = maxY - this.height);
    rs.bottom = true
  }
  if(rs.top || rs.bottom || rs.left || rs.right) {
    return rs;
  }else {
    return false;
  }
}

/**
 * collisionDetection方法 碰撞检测
 * @param {object} target 目标
 * @return {boolean} 如果检测到和目标碰撞了就返回true
 */
BaseCanvasElement.prototype.collisionDetection = function (target) {
  if (!target) return false;
  // 判断四边是否都没有空隙
  if (!(target.x + target.width < this.x) &&
    !(this.x + this.width < target.x) &&
    !(target.y + target.height < this.y) &&
    !(this.y + this.height < target.y)) {
    return true;
  } else {
    return false;
  }
}